package com.dahuyou.tryy.too.simulate.interpreter.parse.clazz.clazzfile;

import java.math.BigInteger;

/**
 * 负责读取class文件信息的类
 */
public class ClassReader {
    /**
     * class文件对应的二进制数据
     */
    private byte[] clazzData;

    public ClassReader(byte[] clazzData) {
        this.clazzData = clazzData;
    }

    /**
     * jvm虚拟机规范，定义了u1，u2，u4三种数据类型,分别表示1字节无符号整数，2字节无符号整数，4字节无符号整数
     * class字节码文件中的各种结构，基本都是通过这3中数据类型来定义的，可参考如下结构体
     * ClassFile {
     *     u4 magic;
     *     u2 minor_version;
     *     u2 major_version;
     *     ...
     * }
     * 说明magic是u4类型，即magic是一个4字节的无符号整数，其他类似
     */
    private final static int JVM_DATA_TYPE_U1 = 1;
    private final static int JVM_DATA_TYPE_U2 = 2;
    private final static int JVM_DATA_TYPE_U4 = 4;

    // u1 转int 读1个字节
    public int readU1() {
//        byte[] val = readByte(1);
        byte[] val = readByte(JVM_DATA_TYPE_U1);
        return byte2int(val);
    }

    // u2 转int 读2个字节
    public int readU2() {
//        byte[] val = readByte(2);
        byte[] val = readByte(JVM_DATA_TYPE_U2);
        return byte2int(val);
    }

    // u4 转long 转long就可以高位填0，就可以作为正数显示
    public long readU4() {
//        byte[] val = readByte(4);
        byte[] val = readByte(JVM_DATA_TYPE_U4);
        String str_hex = new BigInteger(1, val).toString(16);
        return Long.parseLong(str_hex, 16);
    }

    // u4 转int
    public int readU4TInteger(){
        byte[] val = readByte(4);
        return new BigInteger(1, val).intValue();
    }

    public float readUint64TFloat() {
        byte[] val = readByte(8);
        return new BigInteger(1, val).floatValue();
    }

    public long readUint64TLong() {
        byte[] val = readByte(8);
        return new BigInteger(1, val).longValue();
    }

    public double readUint64TDouble() {
        byte[] val = readByte(8);
        return new BigInteger(1, val).doubleValue();
    }

    public int[] readUint16s() {
//        int n = this.readUint16();
        int n = this.readU2();
        int[] s = new int[n];
        for (int i = 0; i < n; i++) {
//            s[i] = this.readUint16();
            s[i] = this.readU2();
        }
        return s;
    }

    public byte[] readBytes(int n) {
        return readByte(n);
    }

    private byte[] readByte(int length) {
        byte[] copy = new byte[length];
        System.arraycopy(clazzData, 0, copy, 0, length);
        System.arraycopy(clazzData, length, clazzData, 0, clazzData.length - length);
        return copy;
    }

    private int byte2int(byte[] val) {
        String str_hex = new BigInteger(1, val).toString(16);
        return Integer.parseInt(str_hex, 16);
    }
}
